/**
 * @author Federico Consoli
 *
 * Released under GNU GPLv3 (http://www.gnu.org/licenses/gpl-3.0.txt)
 */

#include "libreria.h"


Service::servizio* Service::aggiungi_servizio(string nome, string par_in, string par_out, unsigned short port, string ip) {
    reg_sem.scrivi_begin();
    if (testa_elenco_servizi == NULL){
        servizio *first_serv = new servizio;
        first_serv->parametri_in = par_in;
        first_serv->parametri_out = par_out;
        first_serv->nome_servizio = nome;
        first_serv->ip = ip;
        first_serv->port = port;
        first_serv->serv_succ = NULL;
        first_serv->priority = 0;
        testa_elenco_servizi = first_serv;
        reg_sem.scrivi_end();
        return first_serv;
    } 
    else{
        servizio *cerca = testa_elenco_servizi;
        while (cerca){
            if (cerca->nome_servizio == nome && cerca->ip == ip && cerca->port == port) break;
            else cerca = cerca->serv_succ;
        }
        if (cerca == NULL) {
            servizio *nuovo_serv = new servizio;
            nuovo_serv->parametri_in = par_in;
            nuovo_serv->parametri_out = par_out;
            nuovo_serv->nome_servizio = nome;
            nuovo_serv->ip = ip;
            nuovo_serv->port = port;
            nuovo_serv->priority = 0;
            nuovo_serv->serv_succ = testa_elenco_servizi;
            testa_elenco_servizi = nuovo_serv;
            reg_sem.scrivi_end();
            return nuovo_serv;
        } 
        else {
            reg_sem.scrivi_end();
            return NULL;
        }
    }
}

//Rimuove servizio locale

int Service::rimuovi_servizio(string nome, string ip, unsigned short porta){
    reg_sem.scrivi_begin();
    servizio *cerca = testa_elenco_servizi;
    servizio *prec = cerca;
    while (cerca){
        if (cerca->nome_servizio == nome && cerca->ip == ip && cerca->port == porta){
            if (cerca == testa_elenco_servizi)
                testa_elenco_servizi = testa_elenco_servizi->serv_succ;
            else
                prec->serv_succ = cerca->serv_succ;
            delete cerca;
            break;
        }
        prec = cerca;
        cerca = cerca->serv_succ;
    }
    reg_sem.scrivi_end();
    return 0;
}

string Service::display() {
    time_t now = time(NULL);
    string time_string(ctime(&now));
    time_string.erase(time_string.find('\n', 0), 1);
    string out = "[" + time_string + " - " + name + " ] ";
    return out;
}

int Service::elenca_servizi() {
    reg_sem.leggi_begin();
    cout << display() + "List of services\n";
    servizio *cerca = testa_elenco_servizi;
    if (cerca == 0) {
        cout << display() + "Service list is empty\n";
        reg_sem.leggi_end();
        return 0;
    }
    while (cerca) {
        ostringstream port;
        port << cerca->port;
        cout << display() + cerca->nome_servizio + " " + cerca->parametri_in + " " + cerca->parametri_out + " " + cerca->ip + " " + port.str() + '\n';
        cerca = cerca->serv_succ;
    }
    reg_sem.leggi_end();
    return 1;
}

Service::servizio* Service::cerca_servizio(servizio *elem) {
    servizio *cerca = testa_elenco_servizi;
    while (cerca) {
        if (cerca->nome_servizio == elem->nome_servizio && cerca->port == elem->port && cerca->ip == elem->ip) break;
        else cerca = cerca->serv_succ;
    }
    return cerca;
}

Service::~Service() {
    srand((unsigned) time(0));
    servizio*temp = testa_elenco_servizi;
    servizio *elem;
    while (temp) {
        elem = temp;
        temp = temp->serv_succ;
        delete elem;
    }
}


Service::Service(string ip, unsigned short port) {
    testa_elenco_servizi = NULL;
    ip_reg = ip;
    port_reg = port;
}


//Restituisce un oggetto new di tipo Servizio

Service::servizio *Service::ricevi_servizio(int sd) {
    servizio *nuovo_serv = new servizio;
    Connection::recv_s(nuovo_serv->nome_servizio, sd);   
    Connection::recv_s(nuovo_serv->parametri_in, sd);  
    Connection::recv_s(nuovo_serv->parametri_out, sd);   
    Connection::recv_short(nuovo_serv->port, sd); 
    Connection::recv_s(nuovo_serv->ip, sd);
    nuovo_serv->serv_succ = NULL;
    return nuovo_serv;
}

int Service::invia_servizio(servizio *elem, int sd) { 
    Connection::send_s(elem->nome_servizio, sd);
    Connection::send_s(elem->parametri_out, sd);
    Connection::send_s(elem->parametri_in, sd);
    Connection::send_short(elem->port, sd);
    Connection::send_s(elem->ip, sd);
    return 0;
}

#ifdef REGISTRO


Registro::Registro(string ip, unsigned short port) : Service(ip, port) {
    name = "REGISTRO";
    int listenSocket;
    listenSocket = Connection::listen_for(ip_reg, port_reg);
    if (listenSocket == -1)throw 15;
    reg_param.elem = this;
    reg_param.sd = listenSocket;
}

Registro::~Registro(){
    cout << display() + "Closing Register ...\n";
    shutdown(reg_param.sd, SHUT_RDWR);
    for (int k = 0; k < MAXNTHREAD; k++)
        pthread_join(tid[k], NULL);
    close(reg_param.sd);
    if (pthread_mutex_destroy(&m_acc))
        throw 14;
     cout << display() + "Register closed...\n";
}

void* Registro::body(void* arg) {
    threadargs *elem = (threadargs*) arg;
    struct sockaddr_in c_add;
    string client_id;
    int addrlen = sizeof (c_add);
    ostringstream numero_thread;
    numero_thread << elem->num_thread;
    int base_sd = elem->sd;
    Registro*R = elem->elem;
    int sd;
    cout << R->display() + "Thread number " + numero_thread.str() + " ready\n";
    while (1) {
        pthread_mutex_lock(&R->m_acc);
        sd = accept(base_sd, CAST_ADDR(&c_add), (socklen_t*) & addrlen);
        pthread_mutex_unlock(&R->m_acc);
        if (sd == -1) break;
        Connection::recv_s(client_id, sd);
        R->identifica_e_gestisci(sd, client_id);
        close(sd);
    }
    return NULL;
}

void Registro::avvia() {
    if (reg_param.sd == -1) throw 15;
    threadargs*param = &reg_param;
    if (pthread_mutex_init(& m_acc, 0))
        throw 9;
    for (int i = 0; i < MAXNTHREAD; i++) {
        param->num_thread = i;
        if (pthread_create(& tid[i], 0, body, (void *) param))
            throw 13;
    }
    int scelta;
    int quit = 0;
    while (1 && !quit) {
        cout << "\n--------------- [REGISTRO - MENU] ---------------" << endl;
        cout << "0 - Exit" << endl;
        cout << "1 - Show registered services" << endl;
        cout << "--------------- [REGISTRO - MENU] ---------------" << endl;
        cout << "> ";
        cin >> scelta;
        switch (scelta) {
            case 0:
                quit = 1;
                break;
            case 1:
                elenca_servizi();
                break;
            
            default:
                cout << display() +"Case non riconosciuto" << endl;
        }
    }
}





Service::servizio* Registro::assegna_servizio(string nome, string par_in, string par_out) {
    servizio *cerca = testa_elenco_servizi;
    servizio *trovato = 0;
    //ricerca circolare 0-1
    while (cerca) {
        if (cerca->nome_servizio == nome && cerca->parametri_in == par_in && cerca->parametri_out == par_out) {
            if (cerca->priority == 0) {
                cerca->priority = 1;
                trovato = cerca;
                break;
            }
            if (cerca->priority == 1) {
                trovato = cerca;
                cerca->priority = 0;
            }
        }
        cerca = cerca->serv_succ;
    }
    return trovato;
}

void Registro::identifica_e_gestisci(int sd, string client_id) {
    string comando;
    if (client_id == "Client") {
         Connection::recv_s(comando, sd);
        if (comando == "req_serv") {
            reg_sem.scrivi_begin();
            cerca_e_invia(sd); //chiama la assegna_serv e invia serv
            reg_sem.scrivi_end();
        }
    }
    if (client_id == "Server") {
        Connection::send_s("Hello server", sd);
        Connection::recv_s(comando, sd);
        if (comando == "send_serv") {
            servizio *nuovo_serv = Service::ricevi_servizio(sd);
            ostringstream out;
            out << nuovo_serv->port;
            cout << display() + "Received new service '" + nuovo_serv->nome_servizio \
            + "' Input parameter '" + nuovo_serv->parametri_in \
            + "' Output parameter '" + nuovo_serv->parametri_out \
            + "' At ip: " + nuovo_serv->ip \
            + " and port: " + out.str() \
            + "\n";
            //Eseguita nativamente in mutua esclusione
            if (aggiungi_servizio(nuovo_serv->nome_servizio, nuovo_serv->parametri_in, nuovo_serv->parametri_out, nuovo_serv->port, nuovo_serv->ip) == NULL)
                cout << display() + "Service " + nuovo_serv->nome_servizio + " is already on the register\n";
            delete nuovo_serv;
            //Si usa la lettori/scrittori
            elenca_servizi();
        }
        if (comando == "rem_serv") 
            rimuovi_servizio(sd);
    }
}

void Registro::cerca_e_invia(int sd) {
    servizio *trovato, *ricevuto;
    //Ricevo il servizio incompleto dal client
    ricevuto = ricevi_servizio(sd);
    string request;
    request = display() + "Client request for service '" + ricevuto->nome_servizio + "' ";
    if (ricevuto->parametri_in != "")
        request += "'" + ricevuto->parametri_in + "' ";
    if (ricevuto->parametri_out != "")
        request += "'" + ricevuto->parametri_out + "' ";
    request += '\n';
    cout << request;
    trovato = assegna_servizio(ricevuto->nome_servizio, ricevuto->parametri_in, ricevuto->parametri_out);
    string temp_name = ricevuto->nome_servizio;
    delete ricevuto;
    if (trovato) {
        ostringstream out;
        out << trovato->port;
        cout << display() + "Service '" + temp_name + "': found at ip: " \
                 + trovato->ip + " and port: " \
                 + out.str() + '\n';
        Connection::send_s("True", sd);
        invia_servizio(trovato, sd);
    }
    else {
        cout << display() + "Service '" + temp_name + "' not found\n";
        Connection::send_s("False", sd);
    }
}

int Registro::rimuovi_servizio(int sd) {
    servizio *trovato, *ricevuto;
    //Ricevo il servizio completo da rimuovere dal server
    ricevuto = ricevi_servizio(sd);
    ostringstream out;
    out << ricevuto->port;
    cout << display() + "Deleting service '" + ricevuto->nome_servizio \
            + "' Input parameter '" + ricevuto->parametri_in \
            + "' Output parameter '" + ricevuto->parametri_out \
            + "' At ip: " + ricevuto->ip \
            + " and port: " + out.str() \
            + "\n";
    //Solo io posso rimuovere il mio servizio quindi mi serve solo il puntatore 
    //Mutua esclusione
    reg_sem.leggi_begin();
    trovato = Service::cerca_servizio(ricevuto);
    reg_sem.leggi_end();
    if (trovato == NULL) {
        cout << display() + "Impossible to remove the service element " + ricevuto->nome_servizio + ", it is not present\n";
        delete ricevuto;
        return 1;
    }
    //Nativamente in mutua
    Service::rimuovi_servizio(trovato->nome_servizio, trovato->ip, trovato->port);
    cout << display() + "Service  '" + ricevuto->nome_servizio + "' was successfully removed\n";
    elenca_servizi();
    delete ricevuto;
    return 0;
}

#endif


#ifdef SERVER

Service::servizio* Server::cerca_servizio(string nome, string ip, unsigned short port) {
    servizio *cerca = testa_elenco_servizi;
    while (cerca) {
        if (cerca->nome_servizio == nome && cerca->port == port && cerca->ip == ip) break;
        else cerca = cerca->serv_succ;
    }
    if (!cerca) 
           return NULL;
        return cerca;
}

int Server::deregistra_servizio(string nome, string ip, unsigned short port) {
    ostringstream out;
    out << port;
    cout << display() + "Unregister service '" + nome + "' at ip: " + ip + " and port " + out.str() + " started\n";
       int sd;
    string hello;
    servizio *trovato;
    //cerco il servizio
    trovato = cerca_servizio(nome, ip, port);
    if (!trovato) throw 11;
    //Creo la connessione verso il registro servizi
    sd = Connection::connect_to(ip_reg, port_reg);
    if (sd == -1) throw 12;
    //Mi identifico presos il registro servizi
    Connection::send_s("Server", sd);
    Connection::recv_s(hello, sd);
    if (hello == "Hello server") {
        Connection::send_s("rem_serv", sd);
        invia_servizio(trovato, sd);
        cout << display() + "Unregister service '" + nome + "' at ip: " + ip + " and port " + out.str() + " finisched\n";
        return 0;
    } else
        throw 22;
}

int Server::registra_servizio(string nome, string par_in, string par_out, string ip , unsigned short port ) {

    ostringstream out;
    out << port;
    cout << display() + "Register service '" + nome \
            + "' Input parameter '" + par_in \
            + "' Output parameter '" + par_out \
            + "' At ip: " + ip \
            + " and port: " + out.str() \
            + " started\n";
    int sd;
    string hello;
    servizio *nuovo_serv;
    //aggiungo servizio localmente
    nuovo_serv = aggiungi_servizio(nome, par_in, par_out, port, ip);
    //Se è diverso da 0 allora è un nuovo servizio e va avviato
    if (nuovo_serv != NULL)
        avvia_servizio(nuovo_serv);
        //Altrimenti è stato già avviato e bisogna solo registrarlo di nuovo
    else
        nuovo_serv = cerca_servizio(nome, ip, port);
    sd = Connection::connect_to(ip_reg, port_reg);
    if (sd == -1)
        throw 10;
    //Mi identifico presos il registro servizi
    Connection::send_s("Server", sd);
    Connection::recv_s(hello, sd);
    if (hello == "Hello server") {
        Connection::send_s("send_serv", sd);
        invia_servizio(nuovo_serv, sd);
       cout << display() + "Register service '" + nome \
            + "' Input parameter '" + par_in \
            + "' Output parameter '" + par_out \
            + "' At ip: " + ip \
            + " and port: " + out.str() \
            + " finished\n";
    } else
        throw 22;
    close(sd);
    return 0;
}



Server::Server(string ip, unsigned short port) : Service(ip, port) {
   
    indice_sem_servizio = 0;
    elenco_resp = new threadarg*[MAXNSERVICES];
    for (int i = 0; i < MAXNSERVICES; i++)
        if (pthread_mutex_init(&m_acc[i], NULL))
            throw 9;
}

Server::~Server() {
    cout << display() + "Closing Server...\n";
    for (int i = 0; i < indice_sem_servizio; i++) {
        shutdown(elenco_resp[i]->sd, SHUT_RDWR); //Best way to kill the thread!
        for (int k = 0; k < MAXNTHREAD; k++)
            pthread_join(tid[i][k], NULL);
        close(elenco_resp[i]->sd);
        delete elenco_resp[i]->R;
        delete elenco_resp[i];
        if (pthread_mutex_destroy(&m_acc[i])) throw 14;
    }
    delete []elenco_resp;
    cout << display() + "Closing Server done\n";
}

void* Server::body(void* arg) {
    threadarg *wargs = (threadarg*) arg;
    Server *args = wargs->elem;
    int base_sd = wargs->sd;
    Response *R = wargs->R;
    //Indice del semaforo per quella accept per quel servizio
    int ind_sem = wargs->indice_sem;
    struct sockaddr_in c_add;
    int addrlen = sizeof (c_add);
    int sd;
    ostringstream numero_thread;
    numero_thread << wargs->num_thread;
    cout << args->display() + "Thread number " + numero_thread.str() + " ready\n";
    while (1) {
        pthread_mutex_lock(&args->m_acc[ind_sem]);
        sd = accept(base_sd, (struct sockaddr*) (&c_add), (socklen_t*) & addrlen);
        pthread_mutex_unlock(&args->m_acc[ind_sem]);
        if (sd == -1)
           break;
        args->scegli(sd, R);
        close(sd);
    }
    return NULL;
}

void Server::avvia_servizio(servizio* nuovo) {
    //Creo il responce unico, le funzioni saranno gestite dai thread che 
    //si occumano solo di utilizzare le funzioni del responce
    //che viene creato una sola volta per tutti i thread di quel servizio
    Response *R = new Response;
    R->crea_resp(nuovo);
    threadarg *args = new threadarg;
    int listenSocket;
    listenSocket = Connection::listen_for(nuovo->ip, nuovo->port);
    args->elem = this;
    args->sd = listenSocket;
    args->R = R;
    args->indice_sem = indice_sem_servizio;
    cout << display() + "Socket for service " + nuovo->nome_servizio + " ready\n";
    for (int i = 0; i < MAXNTHREAD; i++) {
        args->num_thread = i;
        if (pthread_create(& tid[indice_sem_servizio][i], 0, &Server::body, (void *) args))
            throw 13;
    }
    elenco_resp[indice_sem_servizio] = args;
    indice_sem_servizio++; //Non c'è bisogno della mutua esclusione, i services nel server vengono avviati uno alla volta
    if (listenSocket == -1)
        throw 1;
}

int Server::deregistrati() {
    servizio *cerca = testa_elenco_servizi;
    while (cerca) {
        deregistra_servizio(cerca->nome_servizio, cerca->ip, cerca->port);
        cerca = cerca->serv_succ;
    }
    return 0;
}


#endif



#ifdef CLIENT

int Client::richiedi_servizio(servizio* req_serv) {
    string found;
    //Creo la connessione verso il registro servizi
    int sd = Connection::connect_to(ip_reg, port_reg);
    if (sd == -1) 
        throw 16;
    servizio *ricevuto;
    Connection::send_s("Client", sd);
    //invia richiesta
    Connection::send_s("req_serv", sd);
    invia_servizio(req_serv, sd);
    Connection::recv_s(found, sd);
    
    if (found == "True")
        ricevuto = ricevi_servizio(sd);
    else
        
        ricevuto = NULL;
    if (ricevuto) {
        
        ostringstream out;
        out << ricevuto->port;
        cout << display() + "Service " + ricevuto->nome_servizio + " found at ip: " + ricevuto->ip + " and port: " + out.str() + '\n';
        //Setto ip e porta del servizio
        req_serv->ip = ricevuto->ip;
        req_serv->port = ricevuto->port;
        //Cancello il servizio creato per la ricezione
        delete ricevuto;
        close(sd);
        return 1;
    }
    if (!ricevuto) {
        cout << display() + "Service " + req_serv->nome_servizio + " not found\n";
        
        close(sd);
        return 0;
    }
    return -1;
}


Client::Client(string client_name, string ip, unsigned short port) : Service(ip, port) {
    name = client_name;
    cout << display() + "Build client class done\n";
}

void Client::change_client_name(string name_of_client) {
    name = name_of_client;
    cout << display() + "Name of client changed\n";
}

#endif

Response::Response(string nom) {
    name = nom;
    num_param = 4;
    array_in = new int [num_param];
    array_out = new int [num_param];
    for (int i = 0; i < num_param; i++) {
        array_in[i] = 0;
        array_out[i] = 0;
    }
}

Response::Response(string ip, unsigned short port) : Service(ip, port) {
    num_param = 4;
    array_in = new int [num_param];
    array_out = new int [num_param];
    for (int i = 0; i < num_param; i++) {
        array_in[i] = 0;
        array_out[i] = 0;
    }
}

Response::~Response() {
    delete []array_in;
    delete []array_out;
}

int Response::crea_resp(servizio*crea_ser) {
    cout << display() + "Building Response for service " + crea_ser->nome_servizio + '\n';
    servizio*ser;
    ser = aggiungi_servizio(crea_ser->nome_servizio, crea_ser->parametri_in, crea_ser->parametri_out, crea_ser->port, crea_ser->ip);
    if (ser == NULL) 
        throw 2;
    istringstream list_par(ser->parametri_in);
    string single_par;
    vector<string> param_in;
    vector<string> param_out;
    while (list_par >> single_par)
        param_in.push_back(single_par);
    list_par.clear();
    list_par.str(ser->parametri_out);
    while (list_par >> single_par)
        param_out.push_back(single_par);
    crea_variabili(param_in, param_out);
    cout << display() + "Response to the service " + crea_ser->nome_servizio + " build \n";
    return 0;
}

//restituisce un oggetto di tipo valori con all'interno la risposta vuota ma dimensionata

int Response::crea_variabili(vector<string>& parametri_in, vector<string>& parametri_out) {
    //Dimensiono array_in e array_out

    for (size_t i = 0; i < parametri_in.size(); i++) {
        if (parametri_in.at(i) == "int")
            array_in[0]++;
        else if (parametri_in.at(i) == "string")
            array_in[1]++;
        else if (parametri_in.at(i) == "double")
            array_in[2]++;
        else if (parametri_in.at(i) == "buffer")
            array_in[3]++;
        else throw 3;
    }
    for (size_t i = 0; i < parametri_out.size(); i++) {
        if (parametri_out.at(i) == "int")
            array_out[0]++;
        else if (parametri_out.at(i) == "string")
            array_out[1]++;
        else if (parametri_out.at(i) == "double")
            array_out[2]++;
        else if (parametri_out.at(i) == "buffer")
            array_out[3]++;
        else throw 4;
    }
    return 0;
}


//Riceve i valori nell'ordine 
//0=int 1=string 2=double 3=buffer

Response::valori* Response::ricevi_pacchetto(int sd, string param) {
    cout << display() + "Receiving the response packet...\n";
    valori *pacchetto_val_in = new valori;
    int num_single_param;
    int count = 0;
    for (int i = 0; i < num_param; i++) {
        if (param == "in")num_single_param = array_in[i];
        else num_single_param = array_out[i];
        if (num_single_param) {
            switch (i) {
                case 0:
                    pacchetto_val_in->array = new int [num_single_param];
                    count = 0;
                    while (count < num_single_param) {
                        Connection::recv_int(pacchetto_val_in->array[count], sd);
                        count++;
                    }
                    break;
                case 1:
                    pacchetto_val_in->str = new string[num_single_param];
                    count = 0;
                    while (count < num_single_param) {
                        Connection::recv_s(pacchetto_val_in->str[count], sd);
                        count++;
                    }
                    break;
                case 2:
                    pacchetto_val_in->dou = new double[num_single_param];
                    count = 0;
                    while (count < num_single_param) {
                        Connection::recv_double(pacchetto_val_in->dou[count], sd);
                        count++;
                    }
                    break;
                case 3:
                    pacchetto_val_in->buffer = new char*[num_single_param];
                    pacchetto_val_in->bufflen = new int[num_single_param];
                    count = 0;
                    while (count < num_single_param) {
                        Connection::recv_buff(pacchetto_val_in->buffer[count], pacchetto_val_in->bufflen[count], sd);
                        count++;
                    }
                    break;
                default:
                    throw 5;
            }
        }
    }
    cout << display() + "Response packet received\n";
    return pacchetto_val_in;
}

//Restituisce un pacchetto vuoto da configurare
// Puo essere per i parametri di ingresso o quelli di uscita

Response::valori* Response::pacchetto_vuoto(string param) {
    valori *pacchetto_out = new valori;
    int num_single_param;
    for (int i = 0; i < num_param; i++) {
        if (param == "in")num_single_param = array_in[i];
        else /*(param=="out")*/ num_single_param = array_out[i];
        if (num_single_param) {
            switch (i) {
                case 0:
                    pacchetto_out->array = new int [num_single_param];

                    break;
                case 1:
                    pacchetto_out->str = new string[num_single_param];
                    break;
                case 2:
                    pacchetto_out->dou = new double[num_single_param];
                    break;
                case 3:
                    pacchetto_out->buffer = new char*[num_single_param];
                    pacchetto_out->bufflen = new int[num_single_param];
                    break;
                default:
                    throw 6;
            }
        }
    }
    return pacchetto_out;
}

int Response::invia_pacchetto(Response::valori*pacchetto_out, int sd, string param) {
    cout << display() + "Sending response packet...\n";
    int num_single_param;
    int count = 0;
    for (int i = 0; i < num_param; i++) {
        if (param == "in")num_single_param = array_in[i];
        else num_single_param = array_out[i];
        if (num_single_param) {
            switch (i) {
                case 0:
                    count = 0;
                    while (count < num_single_param) {
                        Connection::send_int(pacchetto_out->array[count], sd);
                        count++;
                    }
                    break;
                case 1:
                    count = 0;
                    while (count < num_single_param) {
                        Connection::send_s(pacchetto_out->str[count], sd);
                        count++;
                    }
                    break;
                case 2:
                    count = 0;
                    while (count < num_single_param) {
                        Connection::send_double(pacchetto_out->dou[count], sd);
                        count++;
                    }
                    break;
                case 3:
                    count = 0;
                    while (count < num_single_param) {
                                               Connection::send_buff(pacchetto_out->buffer[count], pacchetto_out->bufflen[count], sd);
                        count++;
                    }
                    break;
                default:
                    throw 7;
            }
        }
    }
    cout << display() + "Response sent\n";
    return 0;

}

int Response::confronto(int sd) {
    int found;
    servizio *richiesta;
    richiesta = ricevi_servizio(sd);
    if (cerca_servizio(richiesta))
        found = 1;
    else found = 0;
    delete richiesta;
    return found;
}
//Elimina un oggetto di tipo valori

int Response::rem_val(valori* &pacchetto, string tipo) {
    int num_single_param;
    for (int i = 0; i < num_param; i++) {
        if (tipo == "in")num_single_param = array_in[i];
        else num_single_param = array_out[i];
        if (num_single_param) {
            switch (i) {
                case 0:
                    delete []pacchetto->array;
                    break;
                case 1:
                    delete [] pacchetto->str;
                    break;
                case 2:
                    delete [] pacchetto->dou;
                    break;
                case 3:
                    delete [] pacchetto->bufflen;
                    for (int k = 0; k < num_single_param; k++)
                        delete [] pacchetto->buffer[k];
                    delete []pacchetto->buffer;
                    break;
                default:
                    throw 8;
            }
        }
    }
    delete pacchetto;
    return 0;
}

